package com.hue.nio.day02.two;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

/*
    群聊系统的服务端:
        转发用户的消息，监听用户的上线和下线
 */
public class Server {
    public static ServerSocketChannel serverSocketChannel = null;
    public static Selector selector = null;

    //初始化服务端
    public Server() {
        try {
            serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.configureBlocking(false);
            serverSocketChannel.bind(new InetSocketAddress(7777));
            selector = Selector.open();
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
            acceptAndRead();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //与客户端交互的方法
    public void acceptAndRead() {
        try {
            while (selector.select() > 0) {
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = selectionKeys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey key = iterator.next();
                    if (key.isAcceptable()) { //连接事件
                        SocketChannel socketChannel = serverSocketChannel.accept();
                        System.out.println("一个客户端上线：" + socketChannel.getRemoteAddress().toString());
                        socketChannel.configureBlocking(false);
                        socketChannel.register(selector, SelectionKey.OP_READ);
                    } else if (key.isReadable()) { //读事件
                        readAndSend(key);
                    }
                    iterator.remove();
                }
            }
        } catch (IOException e) {
        }
    }

    //读取客户端消息发送到其他客户端
    public void readAndSend(SelectionKey key) {
        SocketChannel socketChannel = (SocketChannel) key.channel();
        ByteBuffer buffer = ByteBuffer.allocate(512);
        //读取数据
        try {
            socketChannel.read(buffer);
            buffer.flip();
            //标记当前位置
            buffer.mark();
            //将读取的数据发送给所有的客户端
            for (SelectionKey key1 : selector.keys()) {
                SelectableChannel channel = key1.channel();
                if (channel != socketChannel && channel != serverSocketChannel) {
                    //将消息发送给这个通道
                    ((SocketChannel) channel).write(buffer);
                    buffer.reset();
                }
            }
        } catch (IOException e) {
            //客户端下线
            try {
                System.out.println(socketChannel.getRemoteAddress() + "下线了");
                //取消注册
                key.cancel();
                //关闭通道
                socketChannel.close();
            } catch (IOException ioException) {
                ioException.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        new Server();
    }
}
